// Copyright 2011 Jim Xochellis
// Licensed under the Apache License, Version 2.0 
// (http://www.apache.org/licenses/LICENSE-2.0)
 
#ifndef __PROF_ITERATOR_H__
#define __PROF_ITERATOR_H__

#include "prof_events.h"
#include <iterator>

//---------------------------------------------------------------

namespace generic_profiling
{

//prof_iterator has been derived from the reverce_iterator of the SGI STL v3.3
//http://www.sgi.com/tech/stl/

template <typename _WI>
class prof_iterator
{
public:
	typedef _WI wrapped_iterator_type;
	typedef typename std::iterator_traits<wrapped_iterator_type>::iterator_category		iterator_category;
	typedef typename std::iterator_traits<wrapped_iterator_type>::value_type			value_type;
	typedef typename std::iterator_traits<wrapped_iterator_type>::difference_type		difference_type;
	typedef typename std::iterator_traits<wrapped_iterator_type>::pointer				pointer;
	typedef typename std::iterator_traits<wrapped_iterator_type>::reference				reference;
	typedef prof_iterator<wrapped_iterator_type>										_Self;

public:
	prof_iterator() {}
	explicit prof_iterator(wrapped_iterator_type __x) : wrapped_iterator_(__x)
	{
		dispatch_event(iterator_pure_creation_event);
	}

	prof_iterator(const _Self& __x) : wrapped_iterator_(__x.wrapped_iterator_)
	{
		dispatch_event(iterator_copy_creation_event);
	}

	template <class _Iter>
	prof_iterator(const prof_iterator<_Iter>& __x)
		: wrapped_iterator_(__x.base())
	{
		dispatch_event(iterator_copy_creation_event);
	}

	_Self& operator=(const _Self &__x)
	{
		wrapped_iterator_ = __x.wrapped_iterator_;
		dispatch_event(iterator_copy_assignment_event);
		return (*this);
	}

	wrapped_iterator_type base() const
	{
		return wrapped_iterator_;
	}

	reference operator*() const
	{
		dispatch_event(iterator_dereference_event);
		return *wrapped_iterator_;
	}

	pointer operator->() const
	{
		//iterator_dereference_event will be dispatched
		return &(operator*());
	}

	_Self& operator++()
	{
		++wrapped_iterator_;
		dispatch_event(iterator_simple_step_event);
		return *this;
	}

	_Self operator++(int)
	{
		_Self __tmp = *this;
		++wrapped_iterator_;
		dispatch_event(iterator_simple_step_event);
		return __tmp;
	}

	_Self& operator--()
	{
		--wrapped_iterator_;
		dispatch_event(iterator_simple_step_event);
		return *this;
	}

	_Self operator--(int)
	{
		_Self __tmp = *this;
		--wrapped_iterator_;

		dispatch_event(iterator_simple_step_event);
		return __tmp;
	}

	_Self operator+(difference_type __n) const
	{
		dispatch_event(iterator_long_step_event);
		return _Self(wrapped_iterator_ + __n);
	}

	_Self& operator+=(difference_type __n)
	{
		dispatch_event(iterator_long_step_event);
		wrapped_iterator_ += __n; return *this;
	}

	_Self& operator-=(difference_type __n)
	{
		dispatch_event(iterator_long_step_event);
		wrapped_iterator_ -= __n; return *this;
	}

	reference operator[](difference_type __n) const
	{
		//iterator_long_step_event will be dispatched
		return *(*this + __n);
	}

private:
	wrapped_iterator_type wrapped_iterator_;
}; //class prof_iterator

//---------------------------------------------------------------

template <class _Iterator>
inline bool operator==(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	dispatch_event(iterator_simple_comparison_event);
	return __x.base() == __y.base();
}

template <class _Iterator>
inline bool operator<(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	dispatch_event(iterator_simple_comparison_event);
	return __x.base() < __y.base();
}

template <class _Iterator>
inline bool operator!=(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	//iterator_simple_comparison_event will be dispatched
	return !(__x == __y);
}

template <class _Iterator>
inline bool operator>(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	//iterator_simple_comparison_event will be dispatched
	return __y  < __x;
}

template <class _Iterator>
inline bool operator<=(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	//iterator_simple_comparison_event will be dispatched
	return !(__y > __x);
}

template <class _Iterator>
inline bool operator>=(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	//iterator_simple_comparison_event will be dispatched
	return !(__x < __y);
}

template <class _Iterator>
inline typename prof_iterator<_Iterator>::difference_type
operator-(const prof_iterator<_Iterator>& __x, const prof_iterator<_Iterator>& __y)
{
	dispatch_event(iterator_arithmetic_event);
	return __x.base() - __y.base();
}

template <class _Iterator>
inline prof_iterator<_Iterator>
operator-(const prof_iterator<_Iterator>& __x, typename prof_iterator<_Iterator>::difference_type __n)
{
	dispatch_event(iterator_arithmetic_event);
	return prof_iterator<_Iterator>(__x.base() - __n);
}

template <class _Iterator>
inline prof_iterator<_Iterator>
operator+(typename prof_iterator<_Iterator>::difference_type __n, const prof_iterator<_Iterator>& __x)
{
	dispatch_event(iterator_arithmetic_event);
	return prof_iterator<_Iterator>(__x.base() + __n);
}

} //namespace generic_profiling

#endif //__PROF_ITERATOR_H__

//---------------------------------------------------------------
